/* -*- coding: utf-8; tab-width: 4 -*-
vim: ts=4 noet ai */

/**
	Desktopd ClickGuard -- Prevent accidential interaction with Web pages

	Copyright © 2016  Desktopd Project

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

	@license GPL-3.0+
	@file

	Support for Add-on SDK in non-Firefox applications is not yet complete.
*/

'use strict';

const _sdkTabs = require ('sdk/tabs');
const _sdkUi = (() => {try {
	return require ('sdk/ui');
} catch (e) {
	// This may be the case with anything other than Firefox
	console.exception ('sdk/ui is not available:', e);
	return void 0;
}}) ();

const _sdkSimplePrefs = require ('sdk/simple-prefs');
const _sdkHotkeys = require ('sdk/hotkeys');

/*
	TODO: Can we make this transparent to Web contents?
*/
const clickGuard = sdkTab => void (sdkTab.attach ({contentScript: `
'use strict';
try {
	((d, s) => (0
		, s.MozUserFocus = 'ignore'
		, s.MozUserInput = 'none'
		, s.MozUserSelect = 'none'
		, d.body && (d.body.style.pointerEvents = 'none')
			|| (s.pointerEvents = 'none')
	))(document, document.documentElement.style);
} catch (e) {}
`}));

const clickGuardRevert = sdkTab => void (sdkTab.attach ({contentScript: `
'use strict';
try {
	((d, s) => (0
		, s.MozUserFocus = ''
		, s.MozUserInput = ''
		, s.MozUserSelect = ''
		, d.body && (d.body.style.pointerEvents = '', 1)
			|| (s.pointerEvents = '')
	))(document, document.documentElement.style);
} catch (e) {}
`}));


const _toggledTabs = new WeakSet ();
let _sdkActiveTabFallback;
const _getActiveTab = () => {
	const sdkTabs = _sdkTabs;
	let error;

	try {
		const sdkActiveTab = sdkTabs.activeTab;
		if (sdkActiveTab) return sdkActiveTab;
		error = new ReferenceError ('activeTab is not defined');
	} catch (e) {
		error = e;
	}

	// comm-central may throw (likely a bug)
	if (_sdkActiveTabFallback) {
		// may not correct, however...
		return _sdkActiveTabFallback;
	}

	if (1 === sdkTab.length) {
		return Array.from (sdkTabs)[0];
	}

	throw error; // give it up
};

let _toggleButton = () => {
	const sdkActiveTab = _getActiveTab ();

	// fallback
	if (_toggledTabs.has (sdkActiveTab)) {
		_toggledTabs.delete (sdkActiveTab);
		clickGuardRevert (sdkActiveTab);
	} else {
		_toggledTabs.add (sdkActiveTab);
		clickGuard (sdkActiveTab);
	}
}; // XXX: mutable object

try {
	const _sdkButton = _sdkUi.ToggleButton ({__proto__: null
		,id: 'button-clickGuard'
		,label: 'Activate ClickGuard on this tab [accel+alt+G]'
		,icon: './../icon.png'
		,onChange () {
			_toggleButton ();
		}
	});

	_toggleButton = () => {
		const sdkToggleState = _sdkButton.state.bind (_sdkButton);
		const sdkActiveTab = _getActiveTab ();

		sdkToggleState ('window', null);
		sdkToggleState ('tab', {checked: !sdkToggleState ('tab').checked});

		if (sdkToggleState ('tab').checked) {
			if (_toggledTabs.has (sdkActiveTab)) return;

			_toggledTabs.add (sdkActiveTab);
			sdkToggleState ('tab', {checked: true, label: 'ClickGuard enabled on this tab'});
			clickGuard (sdkActiveTab);
		} else {
			if (!_toggledTabs.has (sdkActiveTab)) return;

			_toggledTabs.delete (sdkActiveTab);
			sdkToggleState ('tab', {checked: false}); // Unset label
			clickGuardRevert (sdkActiveTab);
		}
	};
} catch (e) {
	// Fennec probably throws
	console.exception (e);
}

// Note: This is added for Fennec. But who uses hotkeys in mobile?
if (_sdkSimplePrefs.prefs.enableHotkey) {
	_sdkHotkeys.Hotkey ({__proto__: null
		 ,combo: 'accel-alt-g'
		 ,onPress () {
			 _toggleButton ();
		 }
	});
}

_sdkTabs.on ('ready', sdkTab => {
	if (!_toggledTabs.has (sdkTab)) return;
	clickGuard (sdkTab);
});

// Remember the active tab for Thunderbird, Seamonkey, etc.
_sdkTabs.on ('activate', sdkTab => {
	_sdkActiveTabFallback = sdkTab;
});
